package com.example.OnlineStorage.exception;

import com.example.OnlineStorage.pojo.Response.ApiResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.util.HashMap;
import java.util.Map;

/**
 * 全局异常处理器，用于捕获并处理控制器层抛出的各种异常。
 *
 */
@ControllerAdvice
public class GlobalExceptionHandler {
	
	/**
	 * 处理 MethodArgumentNotValidException 异常，即当请求参数不满足验证条件时。
	 *
	 * @param e MethodArgumentNotValidException 异常实例，包含验证结果。
	 * @return ResponseEntity 对象，包含错误信息和HTTP状态码。
	 */
	@ExceptionHandler
	public ResponseEntity<?> MethodArgumentNotValidException ( MethodArgumentNotValidException e ) {
		BindingResult bindingResult = e.getBindingResult( );
		StringBuilder sb = new StringBuilder( );
		if ( bindingResult.hasErrors( ) ) {
			bindingResult.getFieldErrors( ).forEach( fieldError -> sb.append( fieldError.getDefaultMessage( ) ).append( ";" ) );
		}
		Map<String, Object> map = new HashMap<>( );
		map.put( "msg", sb.toString( ).split( ";" ) );
		return ApiResponse.GetApiResponse( ).status( 400 ).body( map ).build( );
	}
	
	/**
	 * 处理 MultipartException 异常，通常发生在文件上传过程中出现问题时。
	 *
	 * @param ex            MultipartException 异常实例。
	 * @param redirectAttrs 重定向属性，可用于向重定向的页面传递消息。
	 * @return ResponseEntity 对象，包含错误信息和HTTP状态码。
	 */
	@ExceptionHandler
	public ResponseEntity<Object> handleMultipartException ( MultipartException ex, RedirectAttributes redirectAttrs ) {
		String errorMessage = "请确保表单提交时设置了正确的Content-Type为multipart/form-data";
		return ApiResponse.GetApiResponse( ).status( 400 ).body( errorMessage ).build( );
	}
	
	/**
	 * 处理 CustomException 异常，这是自定义的业务异常类。
	 *
	 * @param e CustomException 异常实例，包含自定义的错误码和错误信息。
	 * @return ResponseEntity 对象，包含错误信息和自定义的HTTP状态码。
	 */
	@ExceptionHandler
	public ResponseEntity<Object> handleCustomException ( CustomException e ) {
		return ApiResponse.GetApiResponse( ).status( e.getErrorCode( ) ).body( e.getErrorMsg( ) ).build( );
	}
	
	/**
	 * 处理 MaxUploadSizeExceededException 异常，当上传文件大小超过限制时抛出。
	 *
	 * @param e MaxUploadSizeExceededException 异常实例，包含超过大小的信息。
	 * @return ResponseEntity 对象，包含错误信息和HTTP状态码。
	 */
	@ExceptionHandler
	public ResponseEntity<Object> handleMaxUploadSizeExceededException ( MaxUploadSizeExceededException e ) {
		System.out.println( "文件大小超过限制");
		return ApiResponse.GetApiResponse( ).status( 413 ).body( "文件大小超过限制." ).build( );
	}
	
	/**
	 * 请求格式不正确
	 *
	 * @param e HttpMediaTypeNotSupportedException
	 * @return ResponseEntity 对象 ，包含错误信息和HTTP状态码。
	 */
	@ExceptionHandler
	public ResponseEntity<Object> handleHttpMediaTypeNotSupportedException ( HttpMediaTypeNotSupportedException e ) {
		return ApiResponse.GetApiResponse( ).status( 415 ).body( "请求格式不正确.请查看Api文档的要求 对象参数使用 application/json\n" +
				                                                         "普通参数使用 application/x-www-form-urlencoded\n" +
				                                                         "文件上传请使用 multipart/form-data" ).build( );
	}
	
	/**
	 * 请求的application/json格式异常
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(HttpMessageNotReadableException.class)
	public ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex) {
		return ApiResponse.GetApiResponse().status(400).body("请求的application/json格式异常").build();
	}
	
	/**
	 * 请求的参数字段名不符合Api文档的要求
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(MissingServletRequestParameterException.class)
	public ResponseEntity<Object> handleMissingServletRequestParameterException(MissingServletRequestParameterException ex) {
		return ApiResponse.GetApiResponse().status(400).body("请检查请求的参数字段名是否符合Api文档的要求").build();
	}
}
